'************************************************************************************
' Copyright © 2003-2005 Kathleen Dollard
'
' This software is provided 'as-is', without any express or implied warranty. In no 
' event will the author be held liable for any damages arising from the use of this
' software.
' 
' You may use this software for any purpose, including commercial applications, 
' and you may redistribute this software as part of application delivery: however, 
' this copyright notice may not be removed and you may not otherwise redistribute 
' this software directly other than providing a link to wwww.gendotnet.com. 
'
' You may alter this software to better server your needs (I'd like to hear about your 
' changes in order to make the software better). If you alter the softwre, you must  
' clearly mark it as altered and must not be misrepresented as the original software.
' nor wholly your original work.
'*************************************************************************************
Option Strict On
Option Explicit On 

Imports System

Namespace KADGen.CodeGenerationSupport
   Public Class OutputEntryCollection
      Inherits Collections.CollectionBase
      Implements ComponentModel.IBindingList

      Private mIsSorted As Boolean
      Private mDirection As ComponentModel.ListSortDirection
      Private mProperty As ComponentModel.PropertyDescriptor

      'Public Sub New(ByVal nodeList As Xml.XmlNodeList)
      '   For Each node As Xml.XmlNode In nodeList
      '      If TypeOf node Is IStatusInfoEntry Then
      '         Me.List.Add(node)
      '      End If
      '   Next
      'End Sub

      Public Sub Add(ByVal item As IStatusInfoEntry)
         Me.List.Add(item)
      End Sub

      Default Public ReadOnly Property Item(ByVal index As Int32) As IStatusInfoEntry
         Get
            Return CType(Me.List(index), IStatusInfoEntry)
         End Get
      End Property

#Region "IBindingList implementation"
      Public Sub AddIndex( _
               ByVal [property] As System.ComponentModel.PropertyDescriptor) _
               Implements ComponentModel.IBindingList.AddIndex
         ' Not supported
      End Sub

      Public Function AddNew() _
               As Object _
               Implements ComponentModel.IBindingList.AddNew
         ' Not supported 
         Throw New System.NotSupportedException("AddNew is not supported on OutputEntryCollection")
      End Function

      Public ReadOnly Property AllowEdit() _
               As Boolean _
               Implements ComponentModel.IBindingList.AllowEdit
         Get
            Return False
         End Get
      End Property

      Public ReadOnly Property AllowNew() _
               As Boolean _
               Implements ComponentModel.IBindingList.AllowNew
         Get
            Return False
         End Get
      End Property

      Public ReadOnly Property AllowRemove() _
               As Boolean _
               Implements ComponentModel.IBindingList.AllowRemove
         Get
            Return False
         End Get
      End Property

      Public Sub ApplySort( _
               ByVal prop As ComponentModel.PropertyDescriptor, _
               ByVal direction As ComponentModel.ListSortDirection) _
               Implements ComponentModel.IBindingList.ApplySort
         Dim comparer As New ArrayComparer(prop.Name, direction)
         Me.InnerList.Sort(comparer)
         mIsSorted = True
         mDirection = direction
         mProperty = prop
         RaiseEvent ListChanged(Me, New ComponentModel.ListChangedEventArgs(ComponentModel.ListChangedType.Reset, 0))
      End Sub

      Public Function Find( _
               ByVal [property] As System.ComponentModel.PropertyDescriptor, _
               ByVal key As Object) _
               As Integer _
               Implements System.ComponentModel.IBindingList.Find
         ' Not implemented
      End Function

      Public ReadOnly Property IsSorted() _
               As Boolean _
               Implements System.ComponentModel.IBindingList.IsSorted
         Get
            Return mIsSorted
         End Get
      End Property

      Public Event ListChanged( _
               ByVal sender As Object, _
               ByVal e As System.ComponentModel.ListChangedEventArgs) _
               Implements System.ComponentModel.IBindingList.ListChanged

      Public Sub RemoveIndex( _
               ByVal [property] As System.ComponentModel.PropertyDescriptor) _
               Implements System.ComponentModel.IBindingList.RemoveIndex
         ' Not implemeted
      End Sub

      Public Sub RemoveSort() _
               Implements System.ComponentModel.IBindingList.RemoveSort
         mIsSorted = False
         RaiseEvent ListChanged(Me, New ComponentModel.ListChangedEventArgs(ComponentModel.ListChangedType.Reset, 0))
      End Sub

      Public ReadOnly Property SortDirection() _
               As System.ComponentModel.ListSortDirection _
               Implements System.ComponentModel.IBindingList.SortDirection
         Get
            Return mDirection
         End Get
      End Property

      Public ReadOnly Property SortProperty() _
               As System.ComponentModel.PropertyDescriptor _
               Implements System.ComponentModel.IBindingList.SortProperty
         Get
            Return mProperty
         End Get
      End Property

      Public ReadOnly Property SupportsChangeNotification() _
               As Boolean _
               Implements System.ComponentModel.IBindingList.SupportsChangeNotification
         Get
            Return False
         End Get
      End Property

      Public ReadOnly Property SupportsSearching() _
               As Boolean _
               Implements System.ComponentModel.IBindingList.SupportsSearching
         Get
            Return False
         End Get
      End Property

      Public ReadOnly Property SupportsSorting() _
               As Boolean _
               Implements System.ComponentModel.IBindingList.SupportsSorting
         Get
            Return True
         End Get
      End Property
#End Region

      Private Class ArrayComparer
         Implements Collections.IComparer

         Private mPropertyName As String
         Private mPropInfo As Reflection.PropertyInfo
         Private mType As System.Type
         Private mDirection As ComponentModel.ListSortDirection

         Public Sub New( _
                  ByVal propertyName As String, _
                  ByVal direction As ComponentModel.ListSortDirection)
            Dim type As System.Type
            mPropertyName = propertyName
            type = GetType(IStatusInfoEntry)
            mPropInfo = type.GetProperty(mPropertyName)
            mType = mPropInfo.PropertyType
            mDirection = direction
         End Sub
         Public Function Compare( _
                  ByVal x As Object, _
                  ByVal y As Object) _
                  As Integer _
                  Implements System.Collections.IComparer.Compare
            Dim obj1 As System.Object
            Dim obj2 As System.Object
            If mDirection = ComponentModel.ListSortDirection.Ascending Then
               obj1 = x
               obj2 = y
            Else
               obj2 = x
               obj1 = y
            End If
            If TypeOf x Is IStatusInfoEntry And TypeOf y Is IStatusInfoEntry Then
               If mType Is GetType(System.String) Then
                  Return CompareStrings(CStr(mPropInfo.GetValue(obj1, Nothing)), _
                              CStr(mPropInfo.GetValue(obj2, Nothing)))
               ElseIf mType Is GetType(System.DateTime) Then
                  Return CompareDates(CDate(mPropInfo.GetValue(obj1, Nothing)), _
                              CDate(mPropInfo.GetValue(obj2, Nothing)))
               ElseIf GetType(System.Exception).IsAssignableFrom(mType) Then
                  Return CompareExceptions(CType(mPropInfo.GetValue(obj1, Nothing), System.Exception), _
                              CType(mPropInfo.GetValue(obj2, Nothing), System.Exception))
               ElseIf GetType([Enum]).IsAssignableFrom(mType) Then
                  Return CompareInts(CInt(mPropInfo.GetValue(obj1, Nothing)), _
                              CInt(mPropInfo.GetValue(obj2, Nothing)))
               End If
            Else
               Throw New System.Exception("Invalid values passed to ArrayComparer of OutputEntryCollection")
            End If
         End Function
         Private Function CompareStrings( _
                  ByVal s1 As String, _
                  ByVal s2 As String) _
                  As Int32
            If s1 < s2 Then
               Return -1
            ElseIf s1 = s2 Then
               Return 0
            Else
               Return 1
            End If
         End Function

         Private Function CompareDates( _
                  ByVal d1 As DateTime, _
                  ByVal d2 As DateTime) _
                  As Int32
            If d1 < d2 Then
               Return -1
            ElseIf d1 = d2 Then
               Return 0
            Else
               Return 1
            End If
         End Function

         Private Function CompareExceptions( _
                  ByVal e1 As System.Exception, _
                  ByVal e2 As System.Exception) _
                  As Int32
            If e1 Is Nothing OrElse _
                  e1.Message Is Nothing OrElse _
                  e1.Message < e2.Message Then
               Return -1
            ElseIf Not e2 Is Nothing AndAlso _
                  Not e2.Message Is Nothing AndAlso _
                  e1.Message = e2.Message Then
               Return 0
            Else
               Return 1
            End If
         End Function

         Private Function CompareInts( _
                  ByVal i1 As Int32, _
                  ByVal i2 As Int32) _
                  As Int32
            If i1 < i2 Then
               Return -1
            ElseIf i1 = i2 Then
               Return 0
            Else
               Return 1
            End If
         End Function

      End Class
   End Class
End Namespace